/**********************************************************************\

 Copyright 2012 Diggory Blake

 This file is part of klip-engine

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.

\**********************************************************************/

#include "kbasicanimation.h"
#include "kerror.h"
#include "ksprite.h"
#include "kperformance.h"

void kBasicAnimation::play(kSprite* sprite, kSequence* sequence) {
	kBasicSequence* s = sequence->as<kBasicSequence*>();
	if (!s)
		throw kError(_T("Invalid animation sequence!"));

	auto i = _sprites.insert(std::make_pair(sprite, kAnimData())).first;
	i->second.sequence = s;
	i->second.time = s->startTime;
	i->second.speed = 1.0f;
}
void kBasicAnimation::stop(kSprite* sprite) {
	_sprites.erase(sprite);
}
void kBasicAnimation::setSpeed(kSprite* sprite, float speed) {
	auto i = _sprites.find(sprite);
	if (i != _sprites.end())
		i->second.speed = speed;
}
kSequence* kBasicAnimation::createSequence(float frameDuration, int frameStart, int frameEnd, int frameLoop) {
	kBasicSequence* result = new kBasicSequence();

	result->loop = frameLoop != -1;
	result->startTime = frameStart*frameDuration;
	result->loopTime = frameLoop*frameDuration;
	result->endTime = frameEnd*frameDuration;
	
	int firstFrame = result->loop ? std::min(frameStart, frameLoop) : frameStart;
	for (int i = firstFrame; i < frameEnd; i++) {
		result->frames.insert(std::make_pair((i-frameStart)*frameDuration, i));
	}

	kAnimation::createSequence(result);

	return result;
}
kSequence* kBasicAnimation::createSequence(const std::map<float, int>& frames, float startTime, float loopTime, float endTime, bool loop) {
	kBasicSequence* result = new kBasicSequence();
	result->startTime = startTime;
	result->loopTime = loopTime;
	result->endTime = endTime;
	result->frames = frames;
	result->loop = loop;

	kAnimation::createSequence(result);

	return result;
}
void kBasicAnimation::onUpdate(float delta) {
	PERF_QUERY;
	
	for (auto i = _sprites.begin(); i != _sprites.end();) {
		auto j = i++;
		kBasicSequence* sequence = j->second.sequence;

		j->second.time += delta*j->second.speed;
		if (j->second.time >= sequence->endTime)
			if (sequence->loop && (sequence->loopTime < sequence->endTime)) {
				do {
					j->second.time += sequence->loopTime - sequence->endTime;
				} while (j->second.time >= sequence->endTime);
			} else {
				j->first->setFrame(getFrame(sequence, sequence->endTime));
				_sprites.erase(j);
				continue;
			}

		j->first->setFrame(getFrame(sequence, j->second.time));
	}
}
int kBasicAnimation::getFrame(kBasicSequence* sequence, float time) {
	if (!sequence)
		throw kError(_T("Invalid animation sequence!"));

	auto i = sequence->frames.upper_bound(time);
	if (i != sequence->frames.begin())
		i--;

	return i->second;
}
int kBasicAnimation::getFrame(kSequence* sequence, float time) {
	return getFrame(sequence->as<kBasicSequence*>(), time);
}
